package edu.ucsd.cse222b.network;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class EndHost extends NetNode{
	
	private List<NetFlow> flows=new ArrayList<NetFlow>();
	private Map<EndHost, HashMap<RoutingPath, NetFlow>> outgoingPaths=new HashMap<EndHost, HashMap<RoutingPath, NetFlow> >();
	private Map<NetFlow, RoutingPath> schedule=new HashMap<NetFlow, RoutingPath>();
	public EndHost(long id){
		super(id);
	}
	public long getId(){
		return id;
	}
	public List<NetFlow> getFlows(){
		return flows;
	}
	public void setFlows(List<NetFlow> flows){
		this.flows=flows;
	}
	public void addFlow(NetFlow flow){
		flows.add(flow);
	}
	public Map<EndHost, HashMap<RoutingPath, NetFlow> > getOutGoingPaths(){
		return outgoingPaths;
	}
	
	public Map<RoutingPath, NetFlow> getOutgoingPaths(EndHost dst){
		return outgoingPaths.get(dst);
	}
	public void setOutgoingPaths(Map<EndHost, HashMap<RoutingPath, NetFlow> > paths){
		outgoingPaths=paths;
	}
	public void setOutgoingPaths(EndHost dst, HashMap<RoutingPath, NetFlow> paths){
		outgoingPaths.put(dst, paths);
	}
	public void addOutgoingPath(EndHost dst, RoutingPath path){
		if(outgoingPaths.get(dst)==null){
			outgoingPaths.put(dst, new HashMap<RoutingPath, NetFlow>());
		}
		outgoingPaths.get(dst).put(path, null);
	}
	public Map<NetFlow, RoutingPath> getSchedule(){
		return schedule;
	}
	public void scheduleFlows(){
		for(NetFlow flow : flows){
			//TODO: should only consider flows which haven't finished
			Random random=new Random();
			EndHost dst=flow.getDestination();
			RoutingPath pathSelected=null;
			boolean success=false;
			for(RoutingPath path : outgoingPaths.get(dst).keySet()){
				if(outgoingPaths.get(dst).get(path)==null){
					outgoingPaths.get(dst).put(path, flow);
					schedule.put(flow, path);
					pathSelected=path;
					success=true;
				}
			}
			if(!success){
				/*if all paths have been chosen before, then randomly choose a path for the current
				 * flow to be scheduled*/
				int index=random.nextInt(outgoingPaths.get(dst).size());
				int i=0;
				
				for(RoutingPath path : outgoingPaths.get(dst).keySet()){
					if(i++==index){
						outgoingPaths.get(dst).put(path, flow);
						schedule.put(flow, path);
						pathSelected=path;
						success=true;
					}
				}
			}
			for(Link link : pathSelected.getLinks()){
				link.addFlow(flow);
			}
			flow.setLinks(pathSelected.getLinks());
		}
	}
	public void startFlow(NetFlow flow){
		flows.add(flow);
	}
	public String toString(){
		return "h"+id;
	}
}
